#include "Config.hpp"
#include "Camera.hpp"
#include <any>
#include <functional>
#include <mutex>
#include <stb/stb_image.h>
#include <vector>

struct ConnectItem {
  std::function<std::any(VirtualConfig *ptr)> funcGet;
  std::function<void(VirtualConfig *ptr, const std::any &data)> funcSet;
};

BaseConfig::item settingList[] = {
    {0, R"( {"name":"路径" , "strlen":100} )", BaseConfig::item_type::I_STRING,
     false},
    {1, R"( {"name":"宽度" , "range":{"min":0 , "max":1920} } )",
     BaseConfig::item_type::I_LONG, true},
    {2, R"( {"name":"高度" , "range":{"min":0 , "max":1080} } )",
     BaseConfig::item_type::I_LONG, true},
};

VirtualConfig::VirtualConfig(VirtualCamera *camera_) : camera(camera_) {}

std::vector<BaseConfig::item> VirtualConfig::ItemList() {
  return std::vector<BaseConfig::item>(std::begin(settingList),
                                       std::end(settingList));
}

bool VirtualConfig::Get(int id, std::string &value) {
  if (id != 0)
    return false;
  value = camera->imgPath.string();
  return true;
}

bool VirtualConfig::Get(int id, long &value) {
  if (id >= sizeof(settingList))
    return false;
  if (settingList[id].type != BaseConfig::item_type::I_LONG)
    return false;

  switch (id) {
  case 1:
    value = camera->inf.width;
    break;
  case 2:
    value = camera->inf.height;
    break;
  default:
    return false;
    break;
  }
  return true;
}
bool VirtualConfig::Get(int id, double &value) { return false; }
bool VirtualConfig::Get(int id, bool &value) { return false; }
bool VirtualConfig::Set(int id, const std::string &value) {
  if (id != 0)
    return false;
  if (!std::filesystem::exists(value))
    return false;
  int width, height, channel;
  std::unique_ptr<unsigned char, void (*)(unsigned char *)> imgData(
      stbi_load(value.c_str(), &width, &height, &channel, 0),
      [](unsigned char *data) { stbi_image_free(data); });
  if (channel != 1 && channel != 3)
    return false;

  {
    std::lock_guard<std::mutex> lock(camera->imgDataMux);
    camera->inf.width = width;
    camera->inf.height = height;
    camera->inf.size = width * height * channel;
    switch (channel) {
    case 1:
      camera->inf.type = BaseCamera::ImageType::GREY;
      break;
    case 3:
      camera->inf.type = BaseCamera::ImageType::RGB8;
    }
    camera->imgData.swap(imgData);
  }
  return true;
}
bool VirtualConfig::Set(int id, const long &value) { return false; }
bool VirtualConfig::Set(int id, const double &value) { return false; }
bool VirtualConfig::Set(int id, const bool &value) { return false; }
